

module bloquejos (lat1, eALU, lat3, eMEM, lat5, eMUL, lat7, eDIV, salt_incorrecte,
	sizeROB, validBypassA, validBypassB, hihaRA, hihaRB, esLD, STon, esIO, WBinout,
	esCALLS, esRETI, esWRS, clk, reset, reset_FF_ALU, we_FF_FETCH, acabaCALLS, interrup, 
	acabaRETI, acabaWRS, jaCALLSiROBbuit, jaRETIiROBbuit, jaINTERiROBbuit, jaWRSiROBbuit);
	
	input lat1, eALU, lat3, eMEM, lat5, eMUL, lat7, eDIV;
	input salt_incorrecte;
	input[2:0] sizeROB;
	input[1:0] validBypassA, validBypassB;
	input hihaRA, hihaRB;
	input esLD, STon;
	input esIO, WBinout;
	input esCALLS, esRETI, esWRS, interrup;
	input acabaCALLS, acabaRETI, acabaWRS;
	input clk, reset;
	
	output reset_FF_ALU, we_FF_FETCH, jaCALLSiROBbuit, jaRETIiROBbuit, jaINTERiROBbuit, jaWRSiROBbuit;
	
	wire latencia, ROBple, LD_amb_ST, IN_OUT, CALLS, RETI, WRS, dependencia, tot, INTERRUPCIO;
	wire wire_WRSiROBbuit, wire_RETIiROBbuit, wire_CALLSiROBbuit;
	
	assign latencia = ~lat1 && eALU || ~lat3 && eMEM || ~lat5 && eMUL || ~lat7 && eDIV;
	assign ROBple = sizeROB == 3'b111;			 
	assign LD_amb_ST = esLD && STon;
	assign dependencia = hihaRA && validBypassA == 2'b01 || hihaRB && validBypassB == 2'b01;
	assign tot = latencia || ROBple || LD_amb_ST || dependencia || IN_OUT || RETI || CALLS || WRS || INTERRUPCIO;
	
	assign reset_FF_ALU = tot || salt_incorrecte;
	assign we_FF_FETCH = ~tot || salt_incorrecte;
	
	assign jaCALLSiROBbuit = wire_CALLSiROBbuit;
	assign jaRETIiROBbuit = wire_RETIiROBbuit; 
	assign jaINTERiROBbuit = INTERRUPCIO;
	assign jaWRSiROBbuit = wire_WRSiROBbuit;
	
	ccMentreNo acabaINOUT (.opcio0(WBinout),
	.activa_opcio0(esIO),
	.clk(clk),
	.reset(reset),
	.sortida(IN_OUT)
);							

	ccHaAcabat unaCALLS (.haAcabat(acabaCALLS),
	.sizeROB(sizeROB),
	.clk(clk),
	.reset(reset),
	.sortida(wire_CALLSiROBbuit)
);

	ccEsperaQue buitROBperCALLS (.opcio0(sizeROB == 3'b000),
	.activa_opcio0(wire_CALLSiROBbuit),
	.clk(clk),
	.reset(reset),
	.sortida(CALLS)
);					 

	ccHaAcabat unaRETI (.haAcabat(acabaRETI),
	.sizeROB(sizeROB),
	.clk(clk),
	.reset(reset),
	.sortida(wire_RETIiROBbuit)
);

	ccEsperaQue buitROBperRETI (.opcio0(sizeROB == 3'b000),
	.activa_opcio0(wire_RETIiROBbuit),
	.clk(clk),
	.reset(reset),
	.sortida(RETI)
);					

	ccHaAcabat unaWRS (.haAcabat(acabaWRS),
	.sizeROB(sizeROB),
	.clk(clk),
	.reset(reset),
	.sortida(wire_WRSiROBbuit)
);

	ccEsperaQue buitROBperWRS (.opcio0(sizeROB == 3'b000),
	.activa_opcio0(wire_WRSiROBbuit),
	.clk(clk),
	.reset(reset),
	.sortida(WRS)
);		  

ccHaAcabat hihaInterrupcio (.haAcabat(interrup),
	.sizeROB(sizeROB),
	.clk(clk),
	.reset(reset),
	.sortida(INTERRUPCIO)
);
	
endmodule

module ccMentreNo (opcio0, activa_opcio0, clk, reset, sortida);
	
	input opcio0, activa_opcio0, reset, clk;
	output sortida;
	
	wire sortidaMUX, sortidaFF;
	
	assign sortida = ~(sortidaMUX || sortidaFF);
	
	mux2 #(.WIDTH(1)) 
	_mux(.d0(opcio0),
	.d1(1'b1),
	.s(sortidaFF || reset),
	.y(sortidaMUX)
);
	
	ffda #(.n(1)) flipa(.D(sortidaMUX),
		.clk(clk),
	.reset(activa_opcio0 && sortidaMUX),
	.we(1'b1),
	.Q(sortidaFF)
);			   	
	
endmodule

module ccEsperaQue (opcio0, activa_opcio0, clk, reset, sortida);
	
	input opcio0, activa_opcio0, reset, clk;
	output sortida;
	
	wire sortidaMUX, sortidaFF;
	
	assign sortida = ~sortidaFF;
	
	mux2 #(.WIDTH(1)) 
	_mux(.d0(opcio0),
	.d1(1'b1),
	.s(sortidaFF || reset),
	.y(sortidaMUX)
);
	
	ffda #(.n(1)) flipa(.D(sortidaMUX),
		.clk(clk),
	.reset(activa_opcio0 && sortidaFF),
	.we(1'b1),
	.Q(sortidaFF)
);			   	
	
endmodule				   

module ccHaAcabat (haAcabat, sizeROB, clk, reset, sortida);
	
	input haAcabat, reset, clk;
	input[2:0] sizeROB;
	output sortida;
	
	wire sortidaFF, sortidaFinal;
	
	assign sortidaFinal = (~sortidaFF || haAcabat) && sizeROB == 3'b000;
	assign sortida = sortidaFinal;
	
	ffda #(.n(1)) flipa(.D(reset || sortidaFinal || sortidaFF),
		.clk(clk),
	.reset(haAcabat && sortidaFF && ~sortidaFinal),
	.we(1'b1),
	.Q(sortidaFF)
);			   	
	
endmodule